from os.path import realpath, dirname, isdir
from os import environ, system
from time import sleep, strftime, localtime
from urllib.request import urlretrieve
from threading import Thread

from selenium.webdriver.common.by import By
from PyQt5.QtWidgets import QApplication

from .notify import Notify
from .funcs import drive
from .doing_data import DoingWithData


class AnimeDownload():
    def __init__(self):
        super(AnimeDownload, self).__init__()
        self.down = f'{environ["HOME"]}/.cache/anima/downloads'
        self.notify = Notify()
        self.set = DoingWithData('setting').set
        self.default()

    def __startDownload(self, driver, quality, urls, url, count_series,
                           series, name, next, name_dir, data, log,
                           clicker, count=0, repeat=False, breaker=False):
        count, acer = series, 0
        while count > 6:
            if clicker == series // 6 and not breaker: break
            acer = series // 6 - clicker if not breaker else clicker
            self.__stoped("Data collection error!!!")
            if not acer: break
            next.click()
            count, acer = count - 6, acer - 1
        self.percent = 40
        count_series = driver.find_elements(By.CLASS_NAME, 'epizode')
        step, clicker = -1 if count <= 0 else series - 1, series // 6
        if data['anime']['ova'][urls.index(url)] > 0:
            step = -(data['anime']['ova'][urls.index(url)]+1)
        while True:
            click_i = count_series[step].text
            self.__stoped("Data collection error!!!")
            if click_i: break
        count_series[step].click()
        sleep(15)
        self.__stoped("Data collection error!!!")
        iframe = driver.find_elements(By.TAG_NAME, 'iframe')
        for item in range(len(iframe)):
            driver.switch_to.frame(iframe[item])
            down = driver.find_elements(By.CLASS_NAME, 'butt')
            if len(down) == 4: break
            driver.switch_to.default_content()
        down = down[3 if quality else 2]
        let = down.get_attribute("href").split('?')[0].split('/')
        self.percent = 65
        False if isdir(f'{self.down}') else system(f'mkdir -pv "{self.down}"')
        data, notify = self.__download(down.get_attribute('href'), let[-1],
                                    urls, name_dir[0], url, name, series,
                                    data, click_i)
        log = f'{name_dir[0]} - New series {series}'
        driver.switch_to.default_content()
        self.percent = 92
        data['anime']['log'] = log
        self.set(data)
        self.chan = True

        if repeat:
            series += 1
            fl = True if len(count_series) - series > 0 else False
            self.__startDownload(driver, quality, urls, url,
                        count_series, series, name,next, name_dir, data,
                        log, clicker,len(count_series) - series, fl)

    def __parse(self, quality, driver, data, url, digit):
        """ Download series of anime for URL. """
        log, urls = '', data['anime']['urls']
        self.percent = 5
        driver.get(url)
        count_series = driver.find_elements(By.CLASS_NAME, 'epizode')
        name = driver.find_element(By.CLASS_NAME, 'shortstoryHead').text
        next = driver.find_element(By.CLASS_NAME, 'next')
        name_dir = name.split(' /')
        self.percent = 35
        series = digit + 1 + data['anime']['ova'][urls.index(url)]
        clicker = series // 6
        length = len(count_series)
        value = (driver, quality, urls, url, count_series, series,
                 name, next, name_dir, data, log, clicker)

        var = (*value, length - series, True, True) if length > series else \
              (*value, 0, False, True)

        self.__startDownload(*var)
        self.percent = 100

    def __checkUpload(self, f, url, dirs, link, name, series, data, search):
        """ 

            Final step after download of series:
            creating folders, renaming file, moving file in folder.

        """
        curent_time = strftime("%H:%M", localtime())
        names_dir = '_'.join(dirs.split())
        child = 'series' if 'серия' in search else 'ova'
        data['anime'][child][url.index(link)] += 1
        ova = data['anime']['ova'][url.index(link)] if 'О' in search else None
        series = f"ova-{ova}" if 'ОВА' in search else f'{series} серия'
        system(f'notify-send "Вышла {series}! {name}\n{curent_time}"')
        if not isdir(f'{self.down}/{names_dir}'):
            system(f'mkdir -pv "{self.down}/{names_dir}"')
        system(f'mv "{self.down}/_{f}" \
                    "{self.down}/{names_dir}/{names_dir}-{series}.mp4"')
        return data

    def __handleProgress(self, blocknum, blocksize, totalsize):
        """ Getting value for progress bar of download. """
        readed_data = blocknum * blocksize
        if totalsize > 0:
            self.download = int(readed_data * 100 / totalsize)
            if self.download > 89:
                self.percent = 95
            elif self.download > 74:
                self.percent = 89
            elif self.download > 49:
                self.percent = 83
            elif self.download > 24:
                self.percent = 77
            elif self.download > 4:
                self.percent = 71
            self.__stoped("Sorry, no numbers below zero")
            QApplication.processEvents()

    def __stoped(self, name):
        if self.dead: raise Exception(name)

    def __download(self, dow, f, urls, dirs, link, name, serie, data, search):
        """ Starting download. """
        save_loc = f'{self.down}/_{f}'
        try:
            self.downloading = True
            urlretrieve(dow, save_loc, self.__handleProgress)
            data = self.notify.check(data, 'anime', dirs, serie, False)
            notify = data['notify']['notify'] = 'empty' \
                if self.notify.empty(data) else data['notify']['notify']
            data = self.__checkUpload(f, urls, dirs, link, name, serie,
                                      data, search)
        except Exception as e:
            notify, rm = data['notify']['notify'], f'rm {save_loc}'
            system(f'notify-send "Error download: {dirs}\n{e}" && {rm}')
            self.downloading = False
        return data, notify

    def getPercent(self):
        return self.percent

    def getDownload(self):
        return self.download

    def default(self):
        self.dead, self.life, self.chan = False, True, False
        self.downloading = False
        self.percent = self.download = 0

    def breaking(self):
        self.dead, self.life = True, False

    def changed(self):
        self.chan = False

    def run(self, data, tuples):
        """ Start one or all downloads of anime. """
        self.default()
        lcd, index, msg, flag, check = tuples
        self.percent, driver = 1, drive()
        el = [i.split(' > ')[1].split(' - new')[0] 
                    for i in data['notify']['anime']]
        seti = list(set([data['anime']['name'].index(i) for i in el]))
        args = (flag, driver, data, seti) if check else \
               (flag, driver, data, data['anime']['urls'][index], lcd)
        func = self.__all if len(args) < 5 else self.__parse
        var = (index, seti, len(args))
        thread = Thread(target=func, args=args)
        try:
            (thread.start(), thread.join()) if self.__starting(*var) else \
            msg('No data to process!', True, False)
        except Exception as e:
             system(f'notify-send "Function Download error:\n{e}"')
        driver.quit()
        sleep(0.8)
        self.default()

    def __starting(self, ind, seti, arg):
        return True if ind in seti and arg > 4 or seti and arg < 5 else False

    def __all(self, flag, driver, data, seti):
        """ Checking of download all anime. """
        while len(seti) > 0:
            url = data['anime']['urls'][seti[0]]
            series = data['anime']['series'][seti[0]]
            self.__parse(flag, driver, data, url, series)
            seti.remove(seti[0]) if self.downloading else False
            self.downloading = False
            self.life = (None, True)[1] if self.life else \
                        (seti.clear(), True)[1]
